<?php

namespace addons\litestore\model;

use app\common\model\meet\Coupon;
use think\Cache;

/**
 * 购物车管理
 * Class Cart
 */
class CacheCart
{
    /* @var string $error 错误信息 */
    public $error = '';

    /* @var int $user_id 用户id */
    private $user_id;

    /* @var array $cart 购物车列表 */
    private $cart = [];

    /* @var bool $clear 是否清空购物车 */
    private $clear = false;

    /**
     * 构造方法
     * Cart constructor.
     * @param $user_id
     */
    public function __construct($user_id)
    {
        $this->user_id = $user_id;
        $this->cart = Cache::get('cart_' . $this->user_id) ?: [];
    }

    /**
     * 购物车列表
     */
    public function getList($user_id, $ids = '', $delivery_method = 0, $coupon_id = 0)
    {
        // 商品列表
        $goodsList = [];
        $list = [];
        if (!empty($ids)) {
            $ids_arr = explode(',', $ids);

            foreach ($ids_arr as $k => $v) {
                if (isset($this->cart[$v])) {
                    $list[$k] = $this->cart[$v];
                }
            }
        } else {
            $list = $this->cart;
        }

        $goodsIds = array_unique(array_column($list, 'goods_id'));
        foreach ((new Wxlitestoregoods)->getListByIds($goodsIds) as $goods) {
            $goodsList[$goods['goods_id']] = $goods;
        }

        if ($delivery_method == 0) {
            // 当前用户收货城市id
            $defaultcity = Litestoreadress::getdefault($user_id);
            $cityId = $defaultcity ? $defaultcity['city_id'] : null;

            // 是否存在收货地址
            $exist_address = $defaultcity;

        } else {
            $defaultcity = [];
            $cityId = 0;
            $exist_address = [];
        }

        // 商品是否在配送范围
        $intraRegion = true;

        // 购物车商品列表
        $cartList = [];
        foreach ($list as $key => $cart) {
            // 判断商品不存在则自动删除
            if (!isset($goodsList[$cart['goods_id']])) {
                $this->delete($cart['goods_id'], $cart['goods_sku_id']);
                continue;
            }
            /* @var Goods $goods */
            $goods = $goodsList[$cart['goods_id']];
            // 商品sku信息
            $goods['goods_sku_id'] = $cart['goods_sku_id'];
            // 商品sku不存在则自动删除
            if (!$goods['goods_sku'] = $goods->getGoodsSku($cart['goods_sku_id'])) {
                $this->delete($cart['goods_id'], $cart['goods_sku_id']);
                continue;
            }
            $goods['show_error'] = 0;
            // 判断商品是否下架
            if ($goods['goods_status'] !== '10') {
                $goods['show_error'] = 1;
                $goods['show_error_text'] = '已下架';
                $this->setError('很抱歉，商品 [' . $goods['goods_name'] . '] 已下架');
            }
            // 判断商品库存
            if ($cart['goods_num'] > $goods['goods_sku']['stock_num']) {
                $goods['show_error'] = 2;
                $goods['show_error_text'] = '库存不足';
                $this->setError('很抱歉，商品 [' . $goods['goods_name'] . '] 库存不足');
            }
            // 商品单价
            $goods['goods_origin_price'] = $goods['goods_sku']['goods_price'];
            $goods['goods_price'] = $goods['goods_sku']['goods_price'];
            // 商品总价
            $goods['total_num'] = $cart['goods_num'];
            $goods['total_price'] = $total_price = bcmul($goods['goods_origin_price'], $cart['goods_num'], 2);
            // 商品总重量
            $goods['goods_total_weight'] = bcmul($goods['goods_sku']['goods_weight'], $cart['goods_num'], 2);

            if ($delivery_method == 0) {
                // 验证用户收货地址是否存在运费规则中
                if ($intraRegion = $goods['freight']->checkAddress($cityId)) {
                    $goods['express_price'] = $goods['freight']->calcTotalFee(
                        $cart['goods_num'], $goods['goods_total_weight'], $cityId);
                } else {
                    //$goods['show_error'] = 3;
                    //$goods['show_error_text'] = '收货区域无法配送';
                    $exist_address && $this->setError("很抱歉，您的收货地址不在商品 [{$goods['goods_name']}] 的配送范围内");
                }
            } else {
                $goods['express_price'] = 0;
            }

            $cartList[] = $goods->toArray();
        }
        // 商品总金额
        $orderTotalPrice = array_sum(array_column($cartList, 'total_price'));
        if ($delivery_method == 0) {
            // 所有商品的运费金额
            $allExpressPrice = array_column($cartList, 'express_price');
            // 订单总运费金额
            $expressPrice = $allExpressPrice ? Litestorefreight::freightRule($allExpressPrice) : 0.00;
        } else {
            // 所有商品的运费金额
            $allExpressPrice = 0;
            // 订单总运费金额
            $expressPrice = 0;
        }

        $coupon_money = 0;
        if ($coupon_id > 0) {
            $coupon_model = new Coupon();
            $coupon_info = $coupon_model->where(['user_id' => $user_id, 'id' => $coupon_id])->find();

            if (empty($coupon_info)) {
                $this->error = __('The coupon does not exist');
                return false;
            }

            if ($coupon_info['status'] != $coupon_model::STATUS_NOT_USE) {
                $this->error = __('This coupon is already in use');
                return false;
            }

            if ($coupon_info['limit'] > $orderTotalPrice) {
                $this->error = __('This coupon does not meet the usage conditions');
                return false;
            }

            if (($coupon_info['end_time'] != 0) && (($coupon_info['end_time']) <= time()) && ($coupon_info['start_time'] > time())) {
                $this->error = __('This coupon is currently unavailable for use');
                return false;
            }

            if (($coupon_info['end_time'] != 0) && ($coupon_info['end_time']) <= time()) {
                $this->error = __('This coupon has expired');
                return false;
            }

            $coupon_money = $coupon_info['money'];
        }

        if ($coupon_money > 0) {
            $total_coupon_money = $coupon_money;
            $avg_coupon_money = bcdiv($coupon_money, count($cartList), 2);

            foreach ($cartList as $key => $value) {
                if ($key >= count($cartList) - 1) {
                    $price = bcsub($value['goods_origin_price'], bcdiv($total_coupon_money, $value['total_num'], 2), 2);
                } else {
                    $price = bcsub($value['goods_origin_price'], bcdiv($avg_coupon_money, $value['total_num'], 2), 2);
                    $total_coupon_money -= $avg_coupon_money;
                }

                $cartList[$key]['goods_price'] = $price >= 0 ? $price : 0;
                $cartList[$key]['total_price']  = bcmul($price, $value['total_num'], 2);
            }
        }


        $order_total_price = bcsub($orderTotalPrice, $coupon_money, 2);

        return [
            'goods_list' => $cartList,                       // 商品列表
            'order_total_num' => $this->getTotalNum(),       // 商品总数量
            'order_total_price' => round($orderTotalPrice, 2),              // 商品总金额 (不含运费)
            'order_pay_price' => bcadd($order_total_price, $expressPrice, 2),    // 实际支付金额
            'coupon_id' => $coupon_id,
            'coupon_money' => $coupon_money,
            'address' => $defaultcity,  // 默认地址
            'exist_address' => $exist_address,      // 是否存在收货地址
            'express_price' => $expressPrice,       // 配送费用
            'intra_region' => $intraRegion,         // 当前用户收货城市是否存在配送规则中
            'has_error' => $this->hasError(),
            'error_msg' => $this->getError(),
            'goods_ids' => implode(',', array_column($cartList,'goods_id'))
        ];
    }

    /**
     * 添加购物车
     * @param $goods_id
     * @param $goods_num
     * @param $goods_sku_id
     * @return bool
     * @throws \think\exception\DbException
     */
    public function add($goods_id, $goods_num, $goods_sku_id)
    {
        // 购物车商品索引
        $index = $goods_id . '_' . $goods_sku_id;
        // 商品信息
        $goods = Wxlitestoregoods::detail($goods_id);
        // 商品sku信息
        $goods['goods_sku'] = $goods->getGoodsSku($goods_sku_id);
        // 判断商品是否下架
        if ($goods['goods_status'] !== '10') {
            $this->setError('很抱歉，该商品已下架');
            return false;
        }
        // 判断商品库存
        $cartGoodsNum = $goods_num + (isset($this->cart[$index]) ? $this->cart[$index]['goods_num'] : 0);
        if ($cartGoodsNum > $goods['goods_sku']['stock_num']) {
            $this->setError('很抱歉，商品库存不足');
            return false;
        }
        $create_time = time();
        $data = compact('goods_id', 'goods_num', 'goods_sku_id', 'create_time');
        if (empty($this->cart)) {
            $this->cart[$index] = $data;
            return true;
        }
        isset($this->cart[$index]) ? $this->cart[$index]['goods_num'] = $cartGoodsNum : $this->cart[$index] = $data;
        return true;
    }

    /**
     * 减少购物车中某商品数量
     * @param $goods_id
     * @param $goods_sku_id
     */
    public function sub($goods_id, $goods_sku_id, $goods_num = 1)
    {
        $index = $goods_id . '_' . $goods_sku_id;
        $this->cart[$index]['goods_num'] > $goods_num && $this->cart[$index]['goods_num'] -= $goods_num;
    }

    /**
     * 删除购物车中指定商品
     * @param $goods_id
     * @param $goods_sku_id
     */
    public function delete($goods_id, $goods_sku_id)
    {
        $index = $goods_id . '_' . $goods_sku_id;
        unset($this->cart[$index]);
    }

    public function deleteByIndex($index)
    {
        unset($this->cart[$index]);
    }

    /**
     * 获取当前用户购物车商品总数量
     * @return int
     */
    public function getTotalNum()
    {
        return array_sum(array_column($this->cart, 'goods_num'));
    }

    /**
     * 析构方法
     * 将cart数据保存到缓存文件
     */
    public function __destruct()
    {
        $this->clear !== true && Cache::set('cart_' . $this->user_id, $this->cart, 86400 * 15);
    }

    /**
     * 清空当前用户购物车
     */
    public function clearAll()
    {
        $this->clear = true;
        Cache::rm('cart_' . $this->user_id);
    }

    /**
     * 设置错误信息
     * @param $error
     */
    private function setError($error)
    {
        empty($this->error) && $this->error = $error;
    }

    /**
     * 是否存在错误
     * @return bool
     */
    private function hasError()
    {
        return !empty($this->error);
    }

    /**
     * 获取错误信息
     * @return string
     */
    public function getError()
    {
        return $this->error;
    }

}
